﻿//统一文件为utf-8编码编译
#pragma execution_character_set("utf-8")
///////////////////////////////////////////////////////////////////////////
// 文件名:     disposewidget.cpp
// 描述:
// 作者:      颜磊
// 创建工程：   AudioComment
// 创建时间:   2024-06-25 18:28
///////////////////////////////////////////////////////////////////////////
#include "disposewidget.h"
#include "ui_disposewidget.h"

#include <QFile>
#include <QMenu>
#include "wavfiletools.h"

DisposeWidget::DisposeWidget(QString filePath,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::DisposeWidget)
{
    ui->setupUi(this);
    qRegisterMetaType<uint64_t>("uint64_t");
    qRegisterMetaType<QVector<short>>("QVector<short>");
    connect(&audioPlayThread,&AudioPlayThread::signal_playIndex,this,&DisposeWidget::slot_playIndex);
    connect(&audioPlayThread,&AudioPlayThread::signal_playState,this,&DisposeWidget::slot_playState);

    connect(ui->spectrogramView,&SpectrogramView::signal_changeSelectState,this,&DisposeWidget::slot_changeSelectState);
    connect(ui->spectrogramView,&SpectrogramView::signal_changeSelectRange,this,&DisposeWidget::slot_changeSelectRange);

    playing = false;
    playNowIndex = 0;
    selectState = false;

    audioFilePath = filePath;
    ui->nowFileName->setText(audioFilePath);
    ui->path->setText(audioFilePath);
    ui->playBandBtn->setEnabled(false);

    audioPlayThread.setAudioFilePath(audioFilePath);
    //读取是否有wav头，读取采样率，wav头
    WAVFILEHEADER wavFileHeader;
    WavFileTools::anlysisWavFileHeader(audioFilePath,wavFileHeader);
    char RiffName[5];
    memset(RiffName,0,5);
    memcpy(RiffName,wavFileHeader.RiffName,sizeof (wavFileHeader.RiffName));
    if(QString(RiffName) == "RIFF"){
        fileHeaderSize = wavFileHeader.fileHeaderSize;
        fileDataSize = wavFileHeader.fileDataSize;
        existsWavHeader = true;
        sampleRate = wavFileHeader.nSampleRate;
        channleNumber = wavFileHeader.nChannleNumber;
        bitsPerSample = wavFileHeader.nBitsPerSample;
    }

    tableModel = new QStandardItemModel();
    tableModel->setHorizontalHeaderItem(0,new QStandardItem(QString("起始")));
    tableModel->setHorizontalHeaderItem(1,new QStandardItem(QString("结束")));
    tableModel->setHorizontalHeaderItem(2,new QStandardItem(QString("内容")));
    ui->tableView->setModel(tableModel);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//单行选中
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//设置单元格不可编辑
    ui->tableView->verticalHeader()->hide();
    ui->tableView->horizontalHeader()->setStretchLastSection(true);//最后一列填充

    languageMap.insert("普通话","chinese");
    languageMap.insert("粤语","cantonese");
    languageMap.insert("英语","english");
    languageMap.insert("俄语","russian");
    languageMap.insert("日语","japanese");
    languageMap.insert("韩语","korean");
    languageMap.insert("马来语","malay");
    languageMap.insert("越南语","vietnamese");
    languageMap.insert("菲律宾语","filipino");
    languageMap.insert("印度尼西亚语","indonesian");
    languageMap.insert("印地语","hindi");


    readJson(); //读取JSON数据
    if(existsWavHeader){
        ui->headerLen->setValue(fileHeaderSize);
        ui->sampleRate->setValue(sampleRate);
        ui->channalNum->setCurrentText(QString::number(channleNumber));
        ui->bitNum->setCurrentText(QString::number(bitsPerSample));
        setWavParam();
    }


}

DisposeWidget::~DisposeWidget()
{
    audioPlayThread.stop();
    audioPlayThread.quit();
    audioPlayThread.wait();
    delete ui;
}

QString DisposeWidget::getAudioFilePath() const
{
    return audioFilePath;
}

void DisposeWidget::setWavParam()
{
    double totalTime =  WavFileTools::indexToTime(sampleRate,channleNumber,bitsPerSample,fileDataSize);
    ui->playTime->setRange(0,totalTime * 1000);
    audioPlayThread.setPlayParam(fileHeaderSize,fileDataSize,sampleRate,channleNumber,bitsPerSample);
    ui->spectrogramView->setFileParam(AudioFileParam(audioFilePath.toStdString(),fileHeaderSize,fileDataSize,sampleRate,channleNumber,bitsPerSample));
    ui->totalTime->setValue(totalTime);
    slot_refMarkBand();
}

void DisposeWidget::slot_playIndex(uint64_t index)
{
    ui->playTime->setValue(WavFileTools::indexToTime(sampleRate,channleNumber,bitsPerSample,index) * 1000);
    ui->spectrogramView->setMarkLineX(WavFileTools::indexToTime(sampleRate,channleNumber,bitsPerSample,index));
    ui->playNowTime->setText(QString::number(WavFileTools::indexToTime(sampleRate,channleNumber,bitsPerSample,index),'f',3)+ " S");
    playNowIndex = index;
}

void DisposeWidget::slot_playState(bool state)
{
    playing = state;
    ui->playBtn->setText(playing ? "停止" : "播放");
    ui->playBandBtn->setEnabled(!playing && selectState);
}

void DisposeWidget::slot_changeSelectState(bool b)
{
    selectState = b;
    ui->playBandBtn->setEnabled(!playing && selectState);
}

void DisposeWidget::slot_changeSelectRange(double selectMinX, double selectMaxX)
{
    selectBegin = selectMinX;
    selectEnd = selectMaxX;
    ui->beginTime->setValue(selectBegin);
    ui->endTime->setValue(selectEnd);
}

void DisposeWidget::slot_editSelectRow()
{
    int selectRow = ui->tableView->selectionModel()->currentIndex().row();
    if(selectRow != -1){
        double startTime = tableModel->index(selectRow,0).data().toDouble();
        double stopTime = tableModel->index(selectRow,1).data().toDouble();
        QString blockText = tableModel->index(selectRow,2).data().toString();
        slot_changeSelectState(true);
        slot_changeSelectRange(startTime,stopTime);
        ui->beginTime->setValue(startTime);
        ui->endTime->setValue(stopTime);
        ui->blockText->setPlainText(blockText);
        ui->spectrogramView->setSelectRangeX(startTime,stopTime);
    }
}

void DisposeWidget::slot_delSelectRow()
{
    int selectRow = ui->tableView->selectionModel()->currentIndex().row();
    if(selectRow != -1){
        tableModel->removeRow(selectRow);
        slot_refMarkBand();
    }
}

void DisposeWidget::slot_clearTableModel()
{
    tableModel->removeRows(0,tableModel->rowCount());
    slot_refMarkBand();
}

void DisposeWidget::slot_refMarkBand()
{
    QList<MarkBand> list;
    MarkBand markBand;
    for (int i=0;i<tableModel->rowCount();i++) {
        QJsonObject sentencesJson;
        markBand = MarkBand(tableModel->index(i,0).data().toDouble(),tableModel->index(i,1).data().toDouble());
        list.append(markBand);
    }
    ui->spectrogramView->setMarkBandList(list);
}

void DisposeWidget::on_playBtn_clicked()
{
    if(playing){
        audioPlayThread.stop();
    }else{
        audioPlayThread.setPlayBeginEnd(0,fileDataSize);
        if(playNowIndex >= fileDataSize){
            audioPlayThread.setPlayNowIndex(0);
        }else{
            audioPlayThread.setPlayNowIndex(playNowIndex);
        }
        audioPlayThread.setLoopPlay(ui->loopPlay->isChecked());
        audioPlayThread.start();
    }
}

void DisposeWidget::on_playBandBtn_clicked()
{
    audioPlayThread.setPlayBeginEnd(WavFileTools::timeToIndex(sampleRate,channleNumber,bitsPerSample,selectBegin),
                                    WavFileTools::timeToIndex(sampleRate,channleNumber,bitsPerSample,selectEnd));
    audioPlayThread.setLoopPlay(ui->loopPlay->isChecked());
    audioPlayThread.start();
}


void DisposeWidget::on_saveBtn_clicked()
{
    writeJson();
}

void DisposeWidget::readJson()
{
    QFileInfo info(audioFilePath);
    QString jsonFilePath = QString("%1/%2.json").arg(info.absolutePath()).arg(info.completeBaseName());
    if(QFile::exists(jsonFilePath)){
        QFile file(jsonFilePath);
        if(file.open(QFile::ReadOnly)){
            QTextStream stream(&file);
            stream.setCodec("UTF-8");
            QString jsonStr = stream.readAll();
            file.close();

            QJsonParseError error;
            QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonStr.toUtf8(),&error);
            if(error.error != QJsonParseError::NoError && jsonDocument.isNull()){
                qDebug() << "格式异常";
            }else{
                QJsonObject mainJsonObj = jsonDocument.object();
                QJsonObject audioJson = mainJsonObj.value("audio").toObject();
                ui->path->setText(audioJson.value("path").toString());
                QString sentence = mainJsonObj.value("sentence").toString();
                ui->allText->setPlainText(sentence);
                QString language = mainJsonObj.value("language").toString();
                ui->languageEdit->setText(language);
                for(QMap<QString,QString>::iterator it=languageMap.begin() ;it != languageMap.end(); ++it ){
                    if(it.value().contains(language)){

                        ui->languageBox->setCurrentText(it.key());
                        break;
                    }
                }

                QJsonArray sentencesJsonArray = mainJsonObj.value("sentences").toArray();
                for (int i=0;i<sentencesJsonArray.size();i++) {
                    QJsonObject sentencesJson = sentencesJsonArray.at(i).toObject();
                    tableModel->insertRow(tableModel->rowCount());
                    int insertRow = tableModel->rowCount() - 1;
                    tableModel->setItem(insertRow,0,new QStandardItem(QString::number(sentencesJson.value("start").toDouble(),'f',3)));
                    tableModel->setItem(insertRow,1,new QStandardItem(QString::number(sentencesJson.value("stop").toDouble(),'f',3)));
                    tableModel->setItem(insertRow,2,new QStandardItem(sentencesJson.value("text").toString()));
                }
            }
        }
    }
}

void DisposeWidget::writeJson()
{
    QFileInfo info(audioFilePath);
    QString jsonFilePath = QString("%1/%2.json").arg(info.absolutePath()).arg(info.completeBaseName());
    QFile file(jsonFilePath);
    if(file.open(QFile::WriteOnly)){
        QJsonObject mainJsonObj;
        QJsonObject audioJson;
        audioJson.insert("path",ui->path->text());
        QJsonArray sentencesJsonArray;
        for (int i=0;i<tableModel->rowCount();i++) {
            QJsonObject sentencesJson;
            sentencesJson.insert("start",tableModel->index(i,0).data().toDouble());
            sentencesJson.insert("stop",tableModel->index(i,1).data().toDouble());
            sentencesJson.insert("text",tableModel->index(i,2).data().toString());
            sentencesJsonArray.append(sentencesJson);
        }
        mainJsonObj.insert("audio",audioJson);
        mainJsonObj.insert("sentence",ui->allText->toPlainText());
        mainJsonObj.insert("language",ui->languageEdit->text());
        mainJsonObj.insert("sentences",sentencesJsonArray);
        mainJsonObj.insert("duration",ui->totalTime->value());
        QJsonDocument jsonDocument;
        jsonDocument.setObject(mainJsonObj);
        QTextStream stream(&file);
        stream.setCodec("UTF-8");
        stream << jsonDocument.toJson();
        file.close();
    }
}

void DisposeWidget::on_tableView_customContextMenuRequested(const QPoint &pos)
{
    QMenu menu(this);
    int selectRow = ui->tableView->selectionModel()->currentIndex().row();
    if(selectRow != -1){
        menu.addAction("编辑",this,&DisposeWidget::slot_editSelectRow);
        menu.addAction("删除",this,&DisposeWidget::slot_delSelectRow);
    }
    if(tableModel->rowCount() > 0){
        menu.addAction("清空",this,&DisposeWidget::slot_clearTableModel);
    }
    menu.exec(QCursor::pos());
}

void DisposeWidget::on_saveToTable_clicked()
{
    int insertRow = ui->tableView->selectionModel()->currentIndex().row();
    if(insertRow != -1){
        if(ui->blockText->toPlainText().isEmpty()){
            //提示不可为空
            return;
        }
        tableModel->setItem(insertRow,0,new QStandardItem(QString::number(ui->beginTime->value(),'f',3)));
        tableModel->setItem(insertRow,1,new QStandardItem(QString::number(ui->endTime->value(),'f',3)));
        tableModel->setItem(insertRow,2,new QStandardItem(ui->blockText->toPlainText()));
        slot_refMarkBand();
    }
}

void DisposeWidget::on_addToTable_clicked()
{
    if(ui->blockText->toPlainText().isEmpty()){
        //提示不可为空
        return;
    }
    tableModel->insertRow(tableModel->rowCount());
    int insertRow = tableModel->rowCount() - 1;
    tableModel->setItem(insertRow,0,new QStandardItem(QString::number(ui->beginTime->value(),'f',3)));
    tableModel->setItem(insertRow,1,new QStandardItem(QString::number(ui->endTime->value(),'f',3)));
    tableModel->setItem(insertRow,2,new QStandardItem(ui->blockText->toPlainText()));
    slot_refMarkBand();
}

void DisposeWidget::on_playTime_valueChanged(int value)
{
    double playNowTime = (double)value / 1000.0;
    playNowIndex = WavFileTools::timeToIndex(sampleRate,channleNumber,bitsPerSample,playNowTime);
    ui->spectrogramView->setMarkLineX(playNowTime);
    ui->playNowTime->setText(QString::number(playNowTime,'f',3)+ " S");
}

void DisposeWidget::on_loopPlay_clicked(bool checked)
{
    audioPlayThread.setLoopPlay(checked);
}

void DisposeWidget::on_setWavParamBtn_clicked()
{
    QFileInfo info(audioFilePath);
    fileHeaderSize = ui->headerLen->value();
    fileDataSize = info.size() - fileHeaderSize;
    sampleRate = ui->sampleRate->value();
    channleNumber = ui->channalNum->currentText().toUInt();
    bitsPerSample = ui->bitNum->currentText().toUInt();
    setWavParam();
}


void DisposeWidget::on_languageBox_currentIndexChanged(const QString &arg1)
{
    ui->languageEdit->setText(languageMap[arg1]);
}
